package com.ckr.shiro;

import cn.hutool.core.bean.BeanUtil;
import com.ckr.entity.User;
import com.ckr.service.UserService;
import com.ckr.util.JwtUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * 登录认证(Authentication)和授权(Authorization)
 *
 * @author Shadowckr
 * @create 2022-02-06 17:14
 */

public class AccountRealm extends AuthorizingRealm {
    @Autowired
    JwtUtils jwtUtils;
    @Autowired
    UserService userService;

    /*
    Realm：Shiro从Realm获取安全数据（如用户，角色，权限），就是说SecurityManager要验证
    用户身份，那么它需要从Realm获取相应的用户进行比较，来确定用户的身份是否合法；也需要从
    Realm获取用户相应的角色、权限，进行验证用户的操作是否能够进行，可以把Realm看成DataSource。

    AccountRealm是shiro进行登录或者权限校验的逻辑所在（核心）。
    重写方法：
    1.doGetAuthorizationInfo():授权逻辑，权限校验。
    2.doGetAuthenticationInfo():认证逻辑，登录认证校验。
    3.supports():为了让realm支持jwt的凭证校验。
     */

    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=>授权逻辑doGetAuthorizationInfo");
        return null;
    }

    /**
     * 认证
     * 通过jwt获取到用户信息，然后判断用户的状态，如果异常就抛出对应的异常信息，
     * 如果正常就封装成SimpleAuthenticationInfo返回给shiro。
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了=>认证逻辑doGetAuthenticationInfo");
        JwtToken jwtToken = (JwtToken) authenticationToken;
        // 获取userId和username
        String userId = (String) jwtUtils.getClaimByToken((String) jwtToken.getPrincipal()).get("userId");
        String username = (String) jwtUtils.getClaimByToken((String) jwtToken.getPrincipal()).get("username");
        // 获取用户内容
        User user = userService.getById(Long.parseLong(userId));
        if (user == null) {
            throw new UnknownAccountException("账户不存在！");
        }
        if (user.getStatus() == -1) {
            throw new LockedAccountException("账户已被锁定！");
        }
        if (!user.getUsername().equals(username)) {
            throw new UnknownAccountException("账户不一致！");
        }

        AccountProfile profile = new AccountProfile();
        // 将user的数据转移到profile
        BeanUtil.copyProperties(user, profile);
        // 用户信息，密钥token，用户名字
        return new SimpleAuthenticationInfo(profile, jwtToken.getCredentials(), getName());
    }

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }
}
